home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / libpng / pngwrite.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-15  |  27.5 KB  |  848 lines

  1.    
  2. /* pngwrite.c - general routines to write a PNG file
  3.  
  4.    libpng 1.0 beta 6 - version 0.96
  5.    For conditions of distribution and use, see copyright notice in png.h
  6.    Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
  7.    Copyright (c) 1996, 1997 Andreas Dilger
  8.    May 12, 1997
  9.    */
  10.  
  11. /* get internal access to png.h */
  12. #define PNG_INTERNAL
  13. #include "png.h"
  14.  
  15. /* Writes all the PNG information.  This is the suggested way to use the
  16.  * library.  If you have a new chunk to add, make a function to write it,
  17.  * and put it in the correct location here.  If you want the chunk written
  18.  * after the image data, put it in png_write_end().  I strongly encurage
  19.  * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
  20.  * the chunk, as that will keep the code from breaking if you want to just
  21.  * write a plain PNG file.  If you have long comments, I suggest writing
  22.  * them in png_write_end(), and compressing them.
  23.  */
  24. void
  25. png_write_info(png_structp png_ptr, png_infop info_ptr)
  26. {
  27.    int i;
  28.  
  29.    png_debug(1, "in png_write_info\n");
  30.    png_write_sig(png_ptr); /* write PNG signature */
  31.    /* write IHDR information. */
  32.    png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
  33.       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
  34.       info_ptr->filter_type, info_ptr->interlace_type);
  35.    /* the rest of these check to see if the valid field has the appropriate
  36.       flag set, and if it does, writes the chunk. */
  37. #if defined(PNG_WRITE_gAMA_SUPPORTED)
  38.    if (info_ptr->valid & PNG_INFO_gAMA)
  39.       png_write_gAMA(png_ptr, info_ptr->gamma);
  40. #endif
  41. #if defined(PNG_WRITE_sBIT_SUPPORTED)
  42.    if (info_ptr->valid & PNG_INFO_sBIT)
  43.       png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
  44. #endif
  45. #if defined(PNG_WRITE_cHRM_SUPPORTED)
  46.    if (info_ptr->valid & PNG_INFO_cHRM)
  47.       png_write_cHRM(png_ptr,
  48.          info_ptr->x_white, info_ptr->y_white,
  49.          info_ptr->x_red, info_ptr->y_red,
  50.          info_ptr->x_green, info_ptr->y_green,
  51.          info_ptr->x_blue, info_ptr->y_blue);
  52. #endif
  53.    if (info_ptr->valid & PNG_INFO_PLTE)
  54.       png_write_PLTE(png_ptr, info_ptr->palette,
  55.          (png_uint_32)info_ptr->num_palette);
  56.    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
  57.       png_error(png_ptr, "Valid palette required for paletted images\n");
  58. #if defined(PNG_WRITE_tRNS_SUPPORTED)
  59.    if (info_ptr->valid & PNG_INFO_tRNS)
  60.       png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
  61.          info_ptr->num_trans, info_ptr->color_type);
  62. #endif
  63. #if defined(PNG_WRITE_bKGD_SUPPORTED)
  64.    if (info_ptr->valid & PNG_INFO_bKGD)
  65.       png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
  66. #endif
  67. #if defined(PNG_WRITE_hIST_SUPPORTED)
  68.    if (info_ptr->valid & PNG_INFO_hIST)
  69.       png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
  70. #endif
  71. #if defined(PNG_WRITE_oFFs_SUPPORTED)
  72.    if (info_ptr->valid & PNG_INFO_oFFs)
  73.       png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
  74.          info_ptr->offset_unit_type);
  75. #endif
  76. #if defined(PNG_WRITE_pCAL_SUPPORTED)
  77.    if (info_ptr->valid & PNG_INFO_pCAL)
  78.       png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
  79.          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
  80.          info_ptr->pcal_units, info_ptr->pcal_params);
  81. #endif
  82. #if defined(PNG_WRITE_pHYs_SUPPORTED)
  83.    if (info_ptr->valid & PNG_INFO_pHYs)
  84.       png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
  85.          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
  86. #endif
  87. #if defined(PNG_WRITE_tIME_SUPPORTED)
  88.    if (info_ptr->valid & PNG_INFO_tIME)
  89.    {
  90.       png_write_tIME(png_ptr, &(info_ptr->mod_time));
  91.       png_ptr->flags |= PNG_FLAG_WROTE_tIME;
  92.    }
  93. #endif
  94. #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
  95.    /* Check to see if we need to write text chunks */
  96.    for (i = 0; i < info_ptr->num_text; i++)
  97.    {
  98.       png_debug2(2, "Writing header text chunk %d, type %d\n", i,
  99.          info_ptr->text[i].compression);
  100.       /* If we want a compressed text chunk */
  101.       if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
  102.       {
  103. #if defined(PNG_WRITE_zTXt_SUPPORTED)
  104.          /* write compressed chunk */
  105.          png_write_zTXt(png_ptr, info_ptr->text[i].key,
  106.             info_ptr->text[i].text, info_ptr->text[i].text_length,
  107.             info_ptr->text[i].compression);
  108. #else
  109.          png_warning(png_ptr, "Unable to write compressed text\n");
  110. #endif
  111.          /* Mark this chunk as written */
  112.          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
  113.       }
  114.       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
  115.       {
  116. #if defined(PNG_WRITE_tEXt_SUPPORTED)
  117.          /* write uncompressed chunk */
  118.          png_write_tEXt(png_ptr, info_ptr->text[i].key,
  119.             info_ptr->text[i].text, info_ptr->text[i].text_length);
  120. #else
  121.          png_warning(png_ptr, "Unable to write uncompressed text\n");
  122. #endif
  123.          /* Mark this chunk as written */
  124.          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
  125.       }
  126.    }
  127. #endif
  128. }
  129.  
  130. /* Writes the end of the PNG file.  If you don't want to write comments or
  131.    time information, you can pass NULL for info.  If you already wrote these
  132.    in png_write_info(), do not write them again here.  If you have long
  133.    comments, I suggest writing them here, and compressing them. */
  134. void
  135. png_write_end(png_structp png_ptr, png_infop info_ptr)
  136. {
  137.    png_debug(1, "in png_write_end\n");
  138.    if (!(png_ptr->mode & PNG_HAVE_IDAT))
  139.       png_error(png_ptr, "No IDATs written into file");
  140.  
  141.    /* see if user wants us to write information chunks */
  142.    if (info_ptr != NULL)
  143.    {
  144.       int i; /* local index variable */
  145. #if defined(PNG_WRITE_tIME_SUPPORTED)
  146.       /* check to see if user has supplied a time chunk */
  147.       if (info_ptr->valid & PNG_INFO_tIME &&
  148.          !(png_ptr->flags & PNG_FLAG_WROTE_tIME))
  149.          png_write_tIME(png_ptr, &(info_ptr->mod_time));
  150. #endif
  151. #if defined(PNG_WRITE_tEXt_SUPPORTED) || defined(PNG_WRITE_zTXt_SUPPORTED)
  152.       /* loop through comment chunks */
  153.       for (i = 0; i < info_ptr->num_text; i++)
  154.       {
  155.          png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
  156.             info_ptr->text[i].compression);
  157.          if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
  158.          {
  159. #if defined(PNG_WRITE_zTXt_SUPPORTED)
  160.             /* write compressed chunk */
  161.             png_write_zTXt(png_ptr, info_ptr->text[i].key,
  162.                info_ptr->text[i].text, info_ptr->text[i].text_length,
  163.                info_ptr->text[i].compression);
  164. #else
  165.             png_warning(png_ptr, "Unable to write compressed text\n");
  166. #endif
  167.             /* Mark this chunk as written */
  168.             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
  169.          }
  170.          else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
  171.          {
  172. #if defined(PNG_WRITE_tEXt_SUPPORTED)
  173.             /* write uncompressed chunk */
  174.             png_write_tEXt(png_ptr, info_ptr->text[i].key,
  175.                info_ptr->text[i].text, info_ptr->text[i].text_length);
  176. #else
  177.             png_warning(png_ptr, "Unable to write uncompressed text\n");
  178. #endif
  179.  
  180.             /* Mark this chunk as written */
  181.             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
  182.          }
  183.       }
  184. #endif
  185.    }
  186.  
  187.    png_ptr->mode |= PNG_AFTER_IDAT;
  188.  
  189.    /* write end of PNG file */
  190.    png_write_IEND(png_ptr);
  191. }
  192.  
  193. #if defined(PNG_WRITE_tIME_SUPPORTED)
  194. void
  195. png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
  196. {
  197.    png_debug(1, "in png_convert_from_struct_tm\n");
  198.    ptime->year = (png_uint_16)(1900 + ttime->tm_year);
  199.    ptime->month = (png_byte)(ttime->tm_mon + 1);
  200.    ptime->day = (png_byte)ttime->tm_mday;
  201.    ptime->hour = (png_byte)ttime->tm_hour;
  202.    ptime->minute = (png_byte)ttime->tm_min;
  203.    ptime->second = (png_byte)ttime->tm_sec;
  204. }
  205.  
  206. void
  207. png_convert_from_time_t(png_timep ptime, time_t ttime)
  208. {
  209.    struct tm *tbuf;
  210.  
  211.    png_debug(1, "in png_convert_from_time_t\n");
  212.    tbuf = gmtime(&ttime);
  213.    png_convert_from_struct_tm(ptime, tbuf);
  214. }
  215. #endif
  216.  
  217. /* Initialize png_ptr structure, and allocate any memory needed */
  218. png_structp
  219. png_create_write_struct(png_const_charp user_png_ver, voidp error_ptr,
  220.    png_error_ptr error_fn, png_error_ptr warn_fn)
  221. {
  222.    png_structp png_ptr;
  223. #ifdef USE_FAR_KEYWORD
  224.    jmp_buf jmpbuf;
  225. #endif
  226.    png_debug(1, "in png_create_write_struct\n");
  227.    if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
  228.    {
  229.       return (png_structp)NULL;
  230.    }
  231. #ifdef USE_FAR_KEYWORD
  232.    if (setjmp(jmpbuf))
  233. #else
  234.    if (setjmp(png_ptr->jmpbuf))
  235. #endif
  236.    {
  237.       png_free(png_ptr, png_ptr->zbuf);
  238.       png_destroy_struct(png_ptr);
  239.       return (png_structp)NULL;
  240.    }
  241. #ifdef USE_FAR_KEYWORD
  242.    png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
  243. #endif
  244.    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
  245.  
  246.    /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
  247.     * we must recompile any applications that use any older library version.
  248.     * For versions after libpng 1.0, we will be compatible, so we need
  249.     * only check the first digit.
  250.     */
  251.    if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
  252.        (png_libpng_ver[0] == '0' && user_png_ver[2] < '9'))
  253.    {
  254.       png_error(png_ptr,
  255.          "Incompatible libpng version in application and library");
  256.    }
  257.  
  258.    /* initialize zbuf - compression buffer */
  259.    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
  260.    png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
  261.  
  262.    png_set_write_fn(png_ptr, NULL, NULL, NULL);
  263.  
  264.    return (png_ptr);
  265. }
  266.  
  267.  
  268. /* Initialize png_ptr structure, and allocate any memory needed */
  269. void
  270. png_write_init(png_structp png_ptr)
  271. {
  272.    jmp_buf tmp_jmp; /* to save current jump buffer */
  273.  
  274.    png_debug(1, "in png_write_init\n");
  275.    /* save jump buffer and error functions */
  276.    png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  277.  
  278.    /* reset all variables to 0 */
  279.    png_memset(png_ptr, 0, sizeof (png_struct));
  280.  
  281.    /* restore jump buffer */
  282.    png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  283.  
  284.    /* initialize zbuf - compression buffer */
  285.    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
  286.    png_ptr->zbuf = png_malloc(png_ptr, png_ptr->zbuf_size);
  287.    png_set_write_fn(png_ptr, NULL, NULL, NULL);
  288.  
  289. #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  290.    png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
  291.       1, NULL, NULL);
  292. #endif
  293. }
  294.  
  295. /* write a few rows of image data.  If the image is interlaced,
  296.    either you will have to write the 7 sub images, or, if you
  297.    have called png_set_interlace_handling(), you will have to
  298.    "write" the image seven times */
  299. void
  300. png_write_rows(png_structp png_ptr, png_bytepp row,
  301.    png_uint_32 num_rows)
  302. {
  303.    png_uint_32 i; /* row counter */
  304.    png_bytepp rp; /* row pointer */
  305.  
  306.    png_debug(1, "in png_write_rows\n");
  307.    /* loop through the rows */
  308.    for (i = 0, rp = row; i < num_rows; i++, rp++)
  309.    {
  310.       png_write_row(png_ptr, *rp);
  311.    }
  312. }
  313.  
  314. /* write the image.  You only need to call this function once, even
  315.    if you are writing an interlaced image. */
  316. void
  317. png_write_image(png_structp png_ptr, png_bytepp image)
  318. {
  319.    png_uint_32 i; /* row index */
  320.    int pass, num_pass; /* pass variables */
  321.    png_bytepp rp; /* points to current row */
  322.  
  323.    png_debug(1, "in png_write_image\n");
  324.    /* intialize interlace handling.  If image is not interlaced,
  325.       this will set pass to 1 */
  326.    num_pass = png_set_interlace_handling(png_ptr);
  327.    /* loop through passes */
  328.    for (pass = 0; pass < num_pass; pass++)
  329.    {
  330.       /* loop through image */
  331.       for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
  332.       {
  333.          png_write_row(png_ptr, *rp);
  334.       }
  335.    }
  336. }
  337.  
  338. /* called by user to write a row of image data */
  339. void
  340. png_write_row(png_structp png_ptr, png_bytep row)
  341. {
  342.    png_debug(1, "in png_write_row\n");
  343.    /* initialize transformations and other stuff if first time */
  344.    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
  345.    {
  346.       png_write_start_row(png_ptr);
  347.    }
  348.  
  349. #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
  350.    /* if interlaced and not interested in row, return */
  351.    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
  352.    {
  353.       switch (png_ptr->pass)
  354.       {
  355.          case 0:
  356.             if (png_ptr->row_number & 7)
  357.             {
  358.                png_write_finish_row(png_ptr);
  359.                return;
  360.             }
  361.             break;
  362.          case 1:
  363.             if ((png_ptr->row_number & 7) || png_ptr->width < 5)
  364.             {
  365.                png_write_finish_row(png_ptr);
  366.                return;
  367.             }
  368.             break;
  369.          case 2:
  370.             if ((png_ptr->row_number & 7) != 4)
  371.             {
  372.                png_write_finish_row(png_ptr);
  373.                return;
  374.             }
  375.             break;
  376.          case 3:
  377.             if ((png_ptr->row_number & 3) || png_ptr->width < 3)
  378.             {
  379.                png_write_finish_row(png_ptr);
  380.                return;
  381.             }
  382.             break;
  383.          case 4:
  384.             if ((png_ptr->row_number & 3) != 2)
  385.             {
  386.                png_write_finish_row(png_ptr);
  387.                return;
  388.             }
  389.             break;
  390.          case 5:
  391.             if ((png_ptr->row_number & 1) || png_ptr->width < 2)
  392.             {
  393.                png_write_finish_row(png_ptr);
  394.                return;
  395.             }
  396.             break;
  397.          case 6:
  398.             if (!(png_ptr->row_number & 1))
  399.             {
  400.                png_write_finish_row(png_ptr);
  401.                return;
  402.             }
  403.             break;
  404.       }
  405.    }
  406. #endif
  407.  
  408.    /* set up row info for transformations */
  409.    png_ptr->row_info.color_type = png_ptr->color_type;
  410.    png_ptr->row_info.width = png_ptr->usr_width;
  411.    png_ptr->row_info.channels = png_ptr->usr_channels;
  412.    png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
  413.    png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
  414.       png_ptr->row_info.channels);
  415.    png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
  416.       (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
  417.  
  418.    png_debug1(4, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
  419.    png_debug1(4, "row_info->width = %d\n", png_ptr->row_info.width);
  420.    png_debug1(4, "row_info->channels = %d\n", png_ptr->row_info.channels);
  421.    png_debug1(4, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
  422.    png_debug1(4, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
  423.    png_debug1(4, "row_info->rowbytes = %d\n", png_ptr->row_info.rowbytes);
  424.  
  425.    /* Copy user's row into buffer, leaving room for filter byte. */
  426.    png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes);
  427.  
  428. #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
  429.    /* handle interlacing */
  430.    if (png_ptr->interlaced && png_ptr->pass < 6 &&
  431.       (png_ptr->transformations & PNG_INTERLACE))
  432.    {
  433.       png_do_write_interlace(&(png_ptr->row_info),
  434.          png_ptr->row_buf + 1, png_ptr->pass);
  435.       /* this should always get caught above, but still ... */
  436.       if (!(png_ptr->row_info.width))
  437.       {
  438.          png_write_finish_row(png_ptr);
  439.          return;
  440.       }
  441.    }
  442. #endif
  443.  
  444.    /* handle other transformations */
  445.    if (png_ptr->transformations)
  446.       png_do_write_transformations(png_ptr);
  447.  
  448.    /* Find a filter if necessary, filter the row and write it out. */
  449.    png_write_find_filter(png_ptr, &(png_ptr->row_info));
  450. }
  451.  
  452. #if defined(PNG_WRITE_FLUSH_SUPPORTED)
  453. /* Set the automatic flush interval or 0 to turn flushing off */
  454. void
  455. png_set_flush(png_structp png_ptr, int nrows)
  456. {
  457.    png_debug(1, "in png_set_flush\n");
  458.    png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
  459. }
  460.  
  461. /* flush the current output buffers now */
  462. void
  463. png_write_flush(png_structp png_ptr)
  464. {
  465.    int wrote_IDAT;
  466.  
  467.    png_debug(1, "in png_write_flush\n");
  468.    /* We have already written out all of the data */
  469.    if (png_ptr->row_number >= png_ptr->num_rows)
  470.      return;
  471.  
  472.    do
  473.    {
  474.       int ret;
  475.  
  476.       /* compress the data */
  477.       ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
  478.       wrote_IDAT = 0;
  479.  
  480.       /* check for compression errors */
  481.       if (ret != Z_OK)
  482.       {
  483.          if (png_ptr->zstream.msg != NULL)
  484.             png_error(png_ptr, png_ptr->zstream.msg);
  485.          else
  486.             png_error(png_ptr, "zlib error");
  487.       }
  488.  
  489.       if (!(png_ptr->zstream.avail_out))
  490.       {
  491.          /* write the IDAT and reset the zlib output buffer */
  492.          png_write_IDAT(png_ptr, png_ptr->zbuf,
  493.                         png_ptr->zbuf_size);
  494.          png_ptr->zstream.next_out = png_ptr->zbuf;
  495.          png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
  496.          wrote_IDAT = 1;
  497.       }
  498.    } while(wrote_IDAT == 1);
  499.  
  500.    /* If there is any data left to be output, write it into a new IDAT */
  501.    if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
  502.    {
  503.       /* write the IDAT and reset the zlib output buffer */
  504.       png_write_IDAT(png_ptr, png_ptr->zbuf,
  505.                      png_ptr->zbuf_size - png_ptr->zstream.avail_out);
  506.       png_ptr->zstream.next_out = png_ptr->zbuf;
  507.       png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
  508.    }
  509.    png_ptr->flush_rows = 0;
  510.    png_flush(png_ptr);
  511. }
  512. #endif /* PNG_WRITE_FLUSH_SUPPORTED */
  513.  
  514. /* free all memory used by the write */
  515. void
  516. png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
  517. {
  518.    png_structp png_ptr = NULL;
  519.    png_infop info_ptr = NULL;
  520.  
  521.    png_debug(1, "in png_destroy_write_struct\n");
  522.    if (png_ptr_ptr != NULL)
  523.       png_ptr = *png_ptr_ptr;
  524.  
  525.    if (info_ptr_ptr != NULL)
  526.       info_ptr = *info_ptr_ptr;
  527.  
  528.    if (info_ptr != NULL)
  529.    {
  530.       png_destroy_struct((png_voidp)info_ptr);
  531.       *info_ptr_ptr = (png_infop)NULL;
  532.    }
  533.  
  534.    if (png_ptr != NULL)
  535.    {
  536.       png_write_destroy(png_ptr);
  537.       png_destroy_struct((png_voidp)png_ptr);
  538.       *png_ptr_ptr = (png_structp)NULL;
  539.    }
  540. }
  541.  
  542.  
  543. /* Free any memory used in png_ptr struct (old method) */
  544. void
  545. png_write_destroy(png_structp png_ptr)
  546. {
  547.    jmp_buf tmp_jmp; /* save jump buffer */
  548.    png_error_ptr error_fn;
  549.    png_error_ptr warning_fn;
  550.    png_voidp error_ptr;
  551.  
  552.    png_debug(1, "in png_write_destroy\n");
  553.    /* free any memory zlib uses */
  554.    deflateEnd(&png_ptr->zstream);
  555.  
  556.    /* free our memory.  png_free checks NULL for us. */
  557.    png_free(png_ptr, png_ptr->zbuf);
  558.    png_free(png_ptr, png_ptr->row_buf);
  559.    png_free(png_ptr, png_ptr->prev_row);
  560.    png_free(png_ptr, png_ptr->sub_row);
  561.    png_free(png_ptr, png_ptr->up_row);
  562.    png_free(png_ptr, png_ptr->avg_row);
  563.    png_free(png_ptr, png_ptr->paeth_row);
  564. #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
  565.    png_free(png_ptr, png_ptr->prev_filters);
  566.    png_free(png_ptr, png_ptr->filter_weights);
  567.    png_free(png_ptr, png_ptr->inv_filter_weights);
  568.    png_free(png_ptr, png_ptr->filter_costs);
  569.    png_free(png_ptr, png_ptr->inv_filter_costs);
  570. #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
  571.  
  572.    /* reset structure */
  573.    png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
  574.  
  575.    error_fn = png_ptr->error_fn;
  576.    warning_fn = png_ptr->warning_fn;
  577.    error_ptr = png_ptr->error_ptr;
  578.  
  579.    png_memset(png_ptr, 0, sizeof (png_struct));
  580.  
  581.    png_ptr->error_fn = error_fn;
  582.    png_ptr->warning_fn = warning_fn;
  583.    png_ptr->error_ptr = error_ptr;
  584.  
  585.    png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
  586. }
  587.  
  588. /* Allow the application to select one or more row filters to use. */
  589. void
  590. png_set_filter(png_structp png_ptr, int method, int filters)
  591. {
  592.    png_debug(1, "in png_set_filter\n");
  593.    /* We allow 'method' only for future expansion of the base filter method. */
  594.    if (method == PNG_FILTER_TYPE_BASE)
  595.    {
  596.       switch (filters & (PNG_ALL_FILTERS | 0x07))
  597.       {
  598.          case 5:
  599.          case 6:
  600.          case 7: png_warning(png_ptr, "Unknown row filter for method 0");
  601.          case PNG_FILTER_VALUE_NONE:  png_ptr->do_filter=PNG_FILTER_NONE; break;
  602.          case PNG_FILTER_VALUE_SUB:   png_ptr->do_filter=PNG_FILTER_SUB;  break;
  603.          case PNG_FILTER_VALUE_UP:    png_ptr->do_filter=PNG_FILTER_UP;   break;
  604.          case PNG_FILTER_VALUE_AVG:   png_ptr->do_filter=PNG_FILTER_AVG;  break;
  605.          case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
  606.          default: png_ptr->do_filter = (png_byte)filters; break;
  607.       }
  608.  
  609.       /* If we have allocated the row_buf, this means we have already started
  610.        * with the image and we should have allocated all of the filter buffers
  611.        * that have been selected.  If prev_row isn't already allocated, then
  612.        * it is too late to start using the filters that need it, since we
  613.        * will be missing the data in the previous row.  If an application
  614.        * wants to start and stop using particular filters during compression,
  615.        * it should start out with all of the filters, and then add and
  616.        * remove them after the start of compression.
  617.        */
  618.       if (png_ptr->row_buf != NULL)
  619.       {
  620.          if (png_ptr->do_filter & PNG_FILTER_SUB && png_ptr->sub_row == NULL)
  621.          {
  622.             png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
  623.                png_ptr->rowbytes + 1);
  624.             png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
  625.          }
  626.  
  627.          if (png_ptr->do_filter & PNG_FILTER_UP && png_ptr->up_row == NULL)
  628.          {
  629.             if (png_ptr->prev_row == NULL)
  630.             {
  631.                png_warning(png_ptr, "Can't add Up filter after starting");
  632.                png_ptr->do_filter &= ~PNG_FILTER_UP;
  633.             }
  634.             else
  635.             {
  636.                png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
  637.                   png_ptr->rowbytes + 1);
  638.                png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
  639.             }
  640.          }
  641.  
  642.          if (png_ptr->do_filter & PNG_FILTER_AVG && png_ptr->avg_row == NULL)
  643.          {
  644.             if (png_ptr->prev_row == NULL)
  645.             {
  646.                png_warning(png_ptr, "Can't add Average filter after starting");
  647.                png_ptr->do_filter &= ~PNG_FILTER_AVG;
  648.             }
  649.             else
  650.             {
  651.                png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
  652.                   png_ptr->rowbytes + 1);
  653.                png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
  654.             }
  655.          }
  656.  
  657.          if (png_ptr->do_filter & PNG_FILTER_PAETH &&
  658.              png_ptr->paeth_row == NULL)
  659.          {
  660.             if (png_ptr->prev_row == NULL)
  661.             {
  662.                png_warning(png_ptr, "Can't add Paeth filter after starting");
  663.                png_ptr->do_filter &= ~PNG_FILTER_PAETH;
  664.             }
  665.             else
  666.             {
  667.                png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
  668.                   png_ptr->rowbytes + 1);
  669.                png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
  670.             }
  671.          }
  672.  
  673.          if (png_ptr->do_filter == PNG_NO_FILTERS)
  674.             png_ptr->do_filter = PNG_FILTER_NONE;
  675.       }
  676.    }
  677.    else
  678.       png_error(png_ptr, "Unknown custom filter method");
  679. }
  680.  
  681. /* This allows us to influence the way in which libpng chooses the "best"
  682.  * filter for the current scanline.  While the "minimum-sum-of-absolute-
  683.  * differences metric is relatively fast and effective, there is some
  684.  * question as to whether it can be improved upon by trying to keep the
  685.  * filtered data going to zlib more consistent, hopefully resulting in
  686.  * better compression. */
  687. #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
  688. void
  689. png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
  690.    int num_weights, png_doublep filter_weights,
  691.    png_doublep filter_costs)
  692. {
  693.    int i;
  694.  
  695.    png_debug(1, "in png_set_filter_heuristics\n");
  696.    if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
  697.    {
  698.       png_warning(png_ptr, "Unknown filter heuristic method");
  699.       return;
  700.    }
  701.  
  702.    if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
  703.    {
  704.       heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
  705.    }
  706.  
  707.    if (num_weights < 0 || filter_weights == NULL ||
  708.       heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
  709.    {
  710.       num_weights = 0;
  711.    }
  712.  
  713.    png_ptr->num_prev_filters = num_weights;
  714.    png_ptr->heuristic_method = heuristic_method;
  715.  
  716.    if (num_weights > 0)
  717.    {
  718.       if (png_ptr->prev_filters == NULL)
  719.       {
  720.          png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
  721.             sizeof(png_byte) * num_weights);
  722.  
  723.          /* To make sure that the weighting starts out fairly */
  724.          for (i = 0; i < num_weights; i++)
  725.          {
  726.             png_ptr->prev_filters[i] = 255;
  727.          }
  728.       }
  729.  
  730.       if (png_ptr->filter_weights == NULL)
  731.       {
  732.          png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
  733.             sizeof(png_uint_16) * num_weights);
  734.  
  735.          png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
  736.             sizeof(png_uint_16) * num_weights);
  737.  
  738.          for (i = 0; i < num_weights; i++)
  739.          {
  740.             png_ptr->inv_filter_weights[i] =
  741.             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
  742.          }
  743.       }
  744.  
  745.       for (i = 0; i < num_weights; i++)
  746.       {
  747.          if (filter_weights[i] < 0.0)
  748.          {
  749.             png_ptr->inv_filter_weights[i] =
  750.             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
  751.          }
  752.          else
  753.          {
  754.             png_ptr->inv_filter_weights[i] =
  755.                (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
  756.             png_ptr->filter_weights[i] =
  757.                (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
  758.          }
  759.       }
  760.    }
  761.  
  762.    /* If, in the future, there are other filter methods, this would
  763.     * need to be based on png_ptr->filter.
  764.     */
  765.    if (png_ptr->filter_costs == NULL)
  766.    {
  767.       png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
  768.          sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
  769.  
  770.       png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
  771.          sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST);
  772.  
  773.       for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
  774.       {
  775.          png_ptr->inv_filter_costs[i] =
  776.          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
  777.       }
  778.    }
  779.  
  780.    /* Here is where we set the relative costs of the different filters.  We
  781.     * should take the desired compression level into account when setting
  782.     * the costs, so that Paeth, for instance, has a high relative cost at low
  783.     * compression levels, while it has a lower relative cost at higher
  784.     * compression settings.  The filter types are in order of increasing
  785.     * relative cost, so it would be possible to do this with an algorithm.
  786.     */
  787.    for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
  788.    {
  789.       if (filter_costs == NULL || filter_costs[i] < 0.0)
  790.       {
  791.          png_ptr->inv_filter_costs[i] =
  792.          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
  793.       }
  794.       else if (filter_costs[i] >= 1.0)
  795.       {
  796.          png_ptr->inv_filter_costs[i] =
  797.             (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
  798.          png_ptr->filter_costs[i] =
  799.             (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
  800.       }
  801.    }
  802. }
  803. #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
  804.  
  805. void
  806. png_set_compression_level(png_structp png_ptr, int level)
  807. {
  808.    png_debug(1, "in png_set_compression_level\n");
  809.    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
  810.    png_ptr->zlib_level = level;
  811. }
  812.  
  813. void
  814. png_set_compression_mem_level(png_structp png_ptr, int mem_level)
  815. {
  816.    png_debug(1, "in png_set_compression_mem_level\n");
  817.    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
  818.    png_ptr->zlib_mem_level = mem_level;
  819. }
  820.  
  821. void
  822. png_set_compression_strategy(png_structp png_ptr, int strategy)
  823. {
  824.    png_debug(1, "in png_set_compression_strategy\n");
  825.    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
  826.    png_ptr->zlib_strategy = strategy;
  827. }
  828.  
  829. void
  830. png_set_compression_window_bits(png_structp png_ptr, int window_bits)
  831. {
  832.    if (window_bits > 15)
  833.       png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
  834.    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
  835.    png_ptr->zlib_window_bits = window_bits;
  836. }
  837.  
  838. void
  839. png_set_compression_method(png_structp png_ptr, int method)
  840. {
  841.    png_debug(1, "in png_set_compression_method\n");
  842.    if (method != 8)
  843.       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
  844.    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
  845.    png_ptr->zlib_method = method;
  846. }
  847.  
  848.